package com.bjpowernode.shop.filter;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.bjpowernode.shop.constants.GatewayConstants;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cloud.gateway.route.RouteLocator;
import org.springframework.cloud.gateway.route.builder.RouteLocatorBuilder;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.core.StringRedisTemplate;
import reactor.core.publisher.Mono;

import java.util.concurrent.TimeUnit;
/*
当前的拦截器作用是将请求转发到指定的微服务中
    [拦截登录请求，拦截/oauth/token]
    登录的请求，申请token的请求
    放行的请求：/oauth/token
    其他的请求：必须具备token才可以进行请求的转发操作
*/
@Configuration //标注在类上，相当于xml配置文件中的<bean's'>标签
public class LoginLocator {

    @Autowired
    private StringRedisTemplate redisTemplate;

    @Bean //标注在方法上，相当于xml配置文件中的<bean>标签
    public RouteLocator routeLocator(RouteLocatorBuilder builder) {
        return builder
                //路由规则集合
                .routes()
                //加入规则
                .route(
                        //路由的id，唯一标识
                        "auth-server",
                        predicateSpec ->
                                //断言规则匹配登录请求： "/oauth/token"
                                predicateSpec.path(GatewayConstants.WHITE_LIST.get(0))
                                        //==修改该请求的响应体数据，并将token存入redis中==
                                        .filters(
                                                //修改该请求的响应体数据
                                                filter -> filter.modifyResponseBody(
                                                        //输入、输出参数的字节码类型
                                                        String.class, String.class,
                                                        //s代表的是原先的请求体数据，通过函数修改请求体数据
                                                        ((exchange, s) -> {
                                                            //解析响应体原json数据
                                                            JSONObject jsonObject = JSON.parseObject(s);
                                                            //存在对应字段则提取
                                                            if (jsonObject.containsKey("access_token")
                                                                    && jsonObject.containsKey("expires_in")) {
                                                                //提取字段对应值[accessToken令牌，expiresIn过期时间]
                                                                String accessToken = jsonObject.getString("access_token");
                                                                long expiresIn = jsonObject.getLongValue("expires_in");
                                                                //存入redis
                                                                redisTemplate.opsForValue().set(
                                                                        GatewayConstants.AUTHORIZATION_PREFIX + accessToken,
                                                                        "",
                                                                        expiresIn,
                                                                        TimeUnit.SECONDS
                                                                );
                                                            }
                                                            //返回响应体数据
                                                            return Mono.just(s);
                                                        })
                                                )
                                        )
                                        //负载均衡访问认证服务器
                                        .uri("lb://auth-server")
                )
                .build();
    }
}
